package com.huawei.java.zother;


import com.huawei.java.pojo.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 判题器
 * @author 金昊霖
 */
public class QuestionJudge {
    static List<Server> servers=new ArrayList<>(5000);
    static Map<Integer, VirtualMachine> virtualMachineMap=new HashMap<>(10000);
    static Request[][] requests;

    public static void main(String[] args) {
//        QuestionJudge.test(serversIds,serverTypes,purchaseServers,addRequestQueue,deleteRequestQueue);
    }
    public static void test(int[] serversIds,Map<String, ServerType> serverTypes,
                     List<SimpleServerType>[] purchaseServers,List<AddRequest>[] addRequestQueue,List<DeleteRequest>[] deleteRequestQueue){
        requests=new Request[addRequestQueue.length][];
        //整合Request
        for (int i=0;i< addRequestQueue.length;i++){
            requests[i]=new Request[addRequestQueue[i].size()+deleteRequestQueue[i].size()];
            for (AddRequest ar:addRequestQueue[i]){
                requests[i][ar.getNumber()]=new Request(1,ar.getNumber(),ar.getVirtualMachineId(),
                        ar.getVirtualMachineType(),ar.getServerId(), ar.getNode());
            }
            for (DeleteRequest dr:deleteRequestQueue[i]){
                requests[i][dr.getNumber()]=new Request(0,dr.getNumber(),dr.getVirtualMachineId());
            }
        }
        Server server;
        VirtualMachine virtualMachine;
        for(int i=0;i<addRequestQueue.length;i++){

            for (SimpleServerType sst:purchaseServers[i]){
                for (Integer j: sst.getServerIds()){
                    servers.add(new Server(serverTypes.get(sst.getName())));
                }
            }
            for (Request r:requests[i]){
                if (r.getType()==1){
                    server=servers.get(serversIds[r.getServerId()]);
                    virtualMachine=new VirtualMachine(r.getVirtualMachineId(),r.getVirtualMachineType());
                    if (r.getNode()==0){
                        server.addAB(virtualMachine);
                    }else if (r.getNode()==1){
                        server.addNodeA(virtualMachine);
                    }else {
                        server.addNodeB(virtualMachine);
                    }
                    virtualMachineMap.put(virtualMachine.getId(),virtualMachine);
                }else{
                    virtualMachine=virtualMachineMap.get(r.getVirtualMachineId());
                    server=servers.get(serversIds[virtualMachine.getServerId()]);
                    server.deleteVirtualMachine(virtualMachine);
                    virtualMachineMap.remove(virtualMachine.getId());
                }
            }
        }
        System.out.println();
    }

}
final class Server {
    static int count=0;
    /**
     * 服务器虚拟id（并非题目要求的真实id）
     */
    private final int id;
    /**
     * 节点A
     */
    private final Node nodeA;
    /**
     * 节点B
     */
    private final Node nodeB;

    private final ServerType serverType;

    public Server(ServerType serverType) {
        id=count++;
        nodeA=new Node(serverType.getCores()>>1,serverType.getMemory()>>1);
        nodeB=new Node(serverType.getCores()>>1,serverType.getMemory()>>1);
        this.serverType = serverType;
    }
    /**
     * 把虚拟机加入结点A
     * @param virtualMachine 虚拟机
     */
    public void addAB(VirtualMachine virtualMachine){
        VirtualMachineType type=virtualMachine.getVirtualMachineType();
        int core=type.getCores()>>1;
        int memory=type.getMemory()>>1;
        int coreA=nodeA.getSurplusCores()-core;
        int memoryA=nodeA.getSurplusMemory()-memory;
        int coreB=nodeB.getSurplusCores()-core;
        int memoryB=nodeB.getSurplusMemory()-memory;

        if (coreA <0|| memoryA <0){
            try {
                throw new Exception("双节点部署虚拟机"+virtualMachine.getId()+"插入服务器"+id+"A结点出错.之前状态：coreA"
                        +nodeA.getSurplusCores()+"  memoryA:"+nodeA.getSurplusMemory()
                        +"插入内核："+core+" 内存:"+memory);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (coreB <0|| memoryB <0){
            try {
                throw new Exception("双节点部署虚拟机"+virtualMachine.getId()+"插入服务器"+id+"B结点出错.之前状态：coreB"
                        +nodeB.getSurplusCores()+"  memoryB:"+nodeB.getSurplusMemory()
                        +"插入内核："+core+" 内存:"+memory);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        nodeA.setSurplusCores(coreA);
        nodeA.setSurplusMemory(memoryA);
        nodeB.setSurplusCores(coreB);
        nodeB.setSurplusMemory(memoryB);
        //设置该虚拟机的serverId和node
        virtualMachine.setServerId(id);
        virtualMachine.setNode(0);

    }
    /**
     * 把虚拟机加入结点A
     * @param v 虚拟机
     */
    public void addNodeA(VirtualMachine v){
        VirtualMachineType type=v.getVirtualMachineType();
        int coreA=nodeA.getSurplusCores()- type.getCores();
        int memoryA=nodeA.getSurplusMemory()-type.getMemory();
        nodeA.setSurplusCores(coreA);
        nodeA.setSurplusMemory(memoryA);
        v.setServerId(id);
        v.setNode(1);
        if (coreA <0|| memoryA <0){
            try {
                throw new Exception("虚拟机"+v.getId()+"插入服务器"+id+"A结点出错.之前状态：coreA"
                        +nodeA.getSurplusCores()+"  memoryA:"+nodeA.getSurplusMemory()
                        +"插入内核："+v.getVirtualMachineType().getCores()+" 内存:"+v.getVirtualMachineType().getMemory());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 把虚拟机加入结点B
     * @param v 虚拟机
     */
    public void addNodeB(VirtualMachine v){
        VirtualMachineType type=v.getVirtualMachineType();
        int coreB =nodeB.getSurplusCores()- type.getCores();
        int memoryB =nodeB.getSurplusMemory()-type.getMemory();
        nodeB.setSurplusCores(coreB);
        nodeB.setSurplusMemory(memoryB);
        v.setServerId(id);
        v.setNode(2);
        if (coreB <0|| memoryB <0){
            try {
                throw new Exception("虚拟机"+v.getId()+"插入服务器"+id+"B结点出错.之前状态：coreB"
                        +nodeB.getSurplusCores()+"  memoryB:"+nodeB.getSurplusMemory()
                        +"插入内核："+v.getVirtualMachineType().getCores()+" 内存:"+v.getVirtualMachineType().getMemory());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public void deleteVirtualMachine(VirtualMachine virtualMachine){
        VirtualMachineType vt = virtualMachine.getVirtualMachineType();
        int cores= vt.getCores();
        int memory= vt.getMemory();
        int node=virtualMachine.getNode();
        //更改节点内的剩余资源
        if (node==0){
            nodeA.setSurplusCores(nodeA.getSurplusCores()+(cores>>1));
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+(memory>>1));
            nodeB.setSurplusCores(nodeB.getSurplusCores()+(cores>>1));
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+(memory>>1));
        }else if (node==1){
            //如果该虚拟机部署在A节点
            nodeA.setSurplusCores(nodeA.getSurplusCores()+cores);
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+memory);
        }else {
            //如果该虚拟机部署在B节点
            nodeB.setSurplusCores(nodeB.getSurplusCores()+cores);
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+memory);
        }
    }
}
final class Request{
    //0表示删除，1表示增加
    private final int type;
    /**
     * 请求在该天的序号
     */
    private final int number;
    /**
     * 虚拟机编号
     */
    private final int virtualMachineId;
    /**
     * 要部署的虚拟机类型
     */
    private  VirtualMachineType virtualMachineType;
    /**
     * 部署的服务器id(如果没有部署则为null)
     */
    private Integer serverId;
    /**
     * 部署的节点，0表示双节点部署，1表示布置在A节点，2表示布置在B节点
     */
    private int node;

    public Request(int type, int number, int virtualMachineId) {
        this.type = type;
        this.number = number;
        this.virtualMachineId = virtualMachineId;
    }

    public Request(int type, int number, int virtualMachineId, VirtualMachineType virtualMachineType, Integer serverId, int node) {
        this.type = type;
        this.number = number;
        this.virtualMachineId = virtualMachineId;
        this.virtualMachineType = virtualMachineType;
        this.serverId = serverId;
        this.node = node;
    }

    public int getType() {
        return type;
    }

    public int getNumber() {
        return number;
    }

    public int getVirtualMachineId() {
        return virtualMachineId;
    }

    public VirtualMachineType getVirtualMachineType() {
        return virtualMachineType;
    }

    public Integer getServerId() {
        return serverId;
    }

    public int getNode() {
        return node;
    }
}
final class Node {
    /**
     * 剩余内核数
     */
    private int surplusCores;

    /**
     * 剩余内存数
     */
    private int surplusMemory;


    public Node(Integer surplusCores, Integer surplusMemory) {
        this.surplusCores = surplusCores;
        this.surplusMemory = surplusMemory;
    }

    public int getSurplusCores() {
        return surplusCores;
    }

    public int getSurplusMemory() {
        return surplusMemory;
    }

    public void setSurplusCores(Integer surplusCores) {
        this.surplusCores = surplusCores;
    }

    public void setSurplusMemory(Integer surplusMemory) {
        this.surplusMemory = surplusMemory;
    }
}
